/*

  Copyright (C) 2010  INRIA, Planète Team

  Authors:
  ------------------------------------------------------------
   Amir Krifa                        :  krifa.amir@gmail.com
   Chadi Barakat                     :  Chadi.Barakat@sophia.inria.fr
  ------------------------------------------------------------

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 3
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#ifndef NODE_H
#define NODE_H

#include <string>
#include "Nodes.h"
#include "Handlers.h"
#include "Link.h"

class Node
{

public:
	
	/**
	 * Constructor. Should be called only by the Nodes class.
	 * 
	 * @param nodeManager Node class that manages this node.
	 * @param eid EID this node represents.
	 */
	Node(Nodes *nodeManager, std::string eid);
	~Node();
	/**
	 * Sets the active link if it's not currently set.
	 * 
	 * @return True if set, false if not set because it's already set.
	 */
	bool setLink(Link *link);
	
	/**
	 * Clear the active link.
	 */
	void clearLink() 
	{
		activeLink = NULL;
	}
	
	/**
	 * Indicates whether the node is associated with a specific link.
	 * 
	 * @param link Link in question.
	 * @return True if associated with the link, else false.
	 */
	bool associated(Link *link) 
	{
		return (activeLink == link);
	}
	
	/**
	 * Indicates whether the node is associated with a link.
	 * 
	 * @return True if associated with some link, else false.
	 */
	bool associated() 
	{
		return (activeLink != NULL);
	}
	
	/**
	 * Finds a link that can take us to the destination EID. This can
	 * be an open link or a defined route. If found we call the link's
	 * conditionalUse() method. The link can choose to do several things:
	 * 
	 *    - Ignore the request, for example if the link is already in
	 *      contact with another EID.
	 *    - Associate this Node with the link, which could happen if the
	 *      link is in contact with the EID but this Node object is not
	 *      associated with the link. This might occur if the Node had
	 *      been previously associated with a different link (e.g. it
	 *      had been using an opportunistic link, or there are multiple
	 *      interfaces).
	 *    - Request that the link be opened. If that is the case then
	 *      this Node object does not get associated with the link, but
	 *      if the link does later open then the association may occur
	 *      at that time.
	 *      
	 * @param excludeLink If not NULL do not try to use the link
	 *    represented by this parameter.
	 * @return The found link, otherwise NULL.
	 */
	Link *findLink(Link *excludeLink);

	/**
	 * Called when a route has been added for this Node. If the Node is not
	 * already actively associated with a Link, possibly open the link. Even
	 * if there is no data to be sent it is generally a good idea to open a
	 * link to exchange meta data and possibly receive bundles.
	 *  
	 * @param link Associated Link object.
	 */
	void routeDefined(Link *link) 
	{
		if (activeLink == NULL) 
		{
			link->conditionalUse(this);
		}
	}
	
	/**
	 * Called to notify the active link -- if there is one -- that a
	 * bundle has been queued. If there is a route for this EID, try
	 * to open the associated link if not already active. This method
	 * is normally called by the policy manager when a bundle has been
	 * queued.
	 * 
	 * @return The link to be notified, or NULL if no link.
	 */
	Link* notifyLink();
	
	/**
	 * The following mirror the LinkedQueue methods for each of the three
	 * defined bundle queues. However, it is the policy manager that
	 * actually defines, implements and manages the queues.
	 */
	
	bool deliveryIsEmpty() 
	{
		return nodeManager->router->policyMgr->deliveryIsEmpty(this);
	}
	
	bool replicaIsEmpty() 
	{
		return nodeManager->router->policyMgr->replicaIsEmpty(this);
	}
	
	bool metadataIsEmpty() 
	{
		return nodeManager->router->policyMgr->metaDataIsEmpty(this);
	}
	
	Bundle* deliveryPoll() 
	{
		return nodeManager->router->policyMgr->deliveryPoll(this);
	}
	
	Bundle* replicaPoll() 
	{
		return nodeManager->router->policyMgr->replicaPoll(this);
	}
	
	Bundle* metadataPoll() 
	{
		return nodeManager->router->policyMgr->metaDataPoll(this);
	}

	std::string eid;
	
private:
	Link * activeLink;
	Nodes * nodeManager;
	
	
};



#endif
